/**
 * 
 */
package example.topic.services.impl;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

import com.mongodb.BasicDBObject;
import com.vanstone.common.debug.MyAssert;
import com.vanstone.fs.FSManager;
import com.vanstone.fs.api.FileException;
import com.vanstone.fs.weedfs.WeedFSFile;

import example.business.api.id.services.IDService;
import example.business.api.topic.Answer;
import example.business.api.topic.AnswerComment;
import example.business.api.topic.Question;
import example.business.api.topic.QuestionComment;
import example.business.api.topic.Tag;
import example.business.api.topic.services.TagService;
import example.business.api.topic.services.TopicService;
import example.common.id.SystemIDSchema;
import example.topic.dal.object.TopicAnswerDO;
import example.topic.dal.object.TopicQuestionDO;

/**
 * @author shipeng
 *
 */
@Service("topicService")
public class TopicServiceImpl implements TopicService {

  @Autowired
  private MongoTemplate mongoTemplate;
  @Autowired
  private TagService tagService;
  @Autowired
  private IDService idService;

  /*
   * (non-Javadoc)
   * 
   * @see example.business.api.topic.services.TopicService#addQuestion(java.lang.String,
   * java.lang.String, java.util.Set, java.util.List)
   */
  @Override
  public Question addQuestion(String content, String remark, Set<String> tagnames, List<File> files) throws FileException {
    MyAssert.hasText(content);

    List<WeedFSFile> weedFSFiles = new ArrayList<>();
    if (files != null && files.size() > 0) {
      for (File file : files) {
        WeedFSFile weedFSFile = FSManager.getInstance().uploadToWeedFS(file);
        weedFSFiles.add(weedFSFile);
      }
    }
    List<Tag> tags = new ArrayList<>();

    if (tagnames != null && tagnames.size() > 0) {
      for (String tagname : tagnames) {
        Tag tag = this.tagService.saveTag(tagname);
        tags.add(tag);
      }
    }

    Question question = new Question();
    question.setId(idService.nextID(SystemIDSchema.Topic_Question));
    question.setSysInsertTime(new Date());
    question.setQuestionContent(content);
    question.setRemark(remark);
    question.setClickcount(0);
    question.setCommentcount(0);
    question.setAnswercount(0);
    question.setTags(tags);
    question.setDeleted(false);
    question.setImageFiles(weedFSFiles);

    this.mongoTemplate.insert(BeanUtil.toTopicQuestionDO(question));
    return question;
  }

  /*
   * (non-Javadoc)
   * 
   * @see example.business.api.topic.services.TopicService#appendQuestionImage(long, java.io.File)
   */
  @Override
  public Question appendQuestionImage(long questionID, File file) throws FileException {
    MyAssert.notNull(file);
    if (!__exist_questionid(questionID)) {
      throw new IllegalArgumentException();
    }
    WeedFSFile weedFSFile = FSManager.getInstance().uploadToWeedFS(file);
    Query query = new Query(Criteria.where("_id").is(questionID));
    Update update = new Update();
    update.addToSet("imageFiles", weedFSFile);
    this.mongoTemplate.updateFirst(query, update, TopicQuestionDO.class);
    return this.getQuestion(questionID);
  }

  /*
   * (non-Javadoc)
   * 
   * @see example.business.api.topic.services.TopicService#deleteQuestionImage(long,
   * java.lang.String)
   */
  @Override
  public void deleteQuestionImage(long questionID, String fileid) {
    if (!this.__exist_questionid(questionID)) {
      throw new IllegalArgumentException();
    }

    Query query_imagefile = new Query();
    Criteria criteria_imagefile = new Criteria();
    criteria_imagefile.andOperator(Criteria.where("_id").is(questionID), Criteria.where("imageFiles.fileid").is(fileid));
    query_imagefile.addCriteria(criteria_imagefile);
    query_imagefile.fields().include("imageFiles.$");

    TopicQuestionDO topicQuestionDO = this.mongoTemplate.findOne(query_imagefile, TopicQuestionDO.class);
    if (topicQuestionDO == null || topicQuestionDO.getImageFiles().size() <= 0) {
      throw new IllegalArgumentException();
    }

    Query query = new Query(Criteria.where("_id").is(questionID));
    Update update = new Update();
    BasicDBObject dbObject = new BasicDBObject("fileid", fileid);
    update.pull("imageFiles", dbObject);
    this.mongoTemplate.updateFirst(query, update, TopicQuestionDO.class);
    topicQuestionDO.getImageFiles().get(0).delete();
  }

  /*
   * (non-Javadoc)
   * 
   * @see example.business.api.topic.services.TopicService#deleteQuestion(long)
   */
  @Override
  public void deleteQuestion(long questionID) {
    if (!__exist_questionid(questionID)) {
      throw new IllegalArgumentException();
    }
    Query query = new Query(Criteria.where("_id").is(questionID));
    Update update = new Update();
    update.set("deleted", true);
    this.mongoTemplate.updateFirst(query, update, TopicQuestionDO.class);
  }

  /*
   * (non-Javadoc)
   * 
   * @see example.business.api.topic.services.TopicService#getQuestion(long)
   */
  @Override
  public Question getQuestion(long questionID) {
    TopicQuestionDO topicQuestionDO = this.mongoTemplate.findById(questionID, TopicQuestionDO.class);
    if (topicQuestionDO == null) {
      return null;
    }
    List<Tag> tags = this.tagService.getTags(topicQuestionDO.getTagids());
    return BeanUtil.toQuestion(topicQuestionDO, tags);
  }

  /*
   * (non-Javadoc)
   * 
   * @see example.business.api.topic.services.TopicService#getQuestions(long, long)
   */
  @Override
  public List<Question> getQuestions(Boolean deleted, long offset, long limit) {
    Query query = new Query();
    if (deleted != null) {
      query.addCriteria(Criteria.where("deleted").is(deleted));
    }
    query.skip((int) offset);
    query.limit((int) limit);

    List<TopicQuestionDO> topicQuestionDOs = this.mongoTemplate.find(query, TopicQuestionDO.class);
    if (topicQuestionDOs == null || topicQuestionDOs.size() <= 0) {
      return null;
    }
    List<Question> questions = new ArrayList<>();
    for (TopicQuestionDO topicQuestionDO : topicQuestionDOs) {
      Question question = BeanUtil.toQuestion(topicQuestionDO, this.tagService.getTags(topicQuestionDO.getTagids()));
      questions.add(question);
    }
    return questions;
  }

  /*
   * (non-Javadoc)
   * 
   * @see example.business.api.topic.services.TopicService#readQuestion(long)
   */
  @Override
  public Question readQuestion(long questionID) {
    Query query = new Query(Criteria.where("_id").is(questionID));
    Update update = new Update().inc("clickcount", 1);
    this.mongoTemplate.updateFirst(query, update, TopicQuestionDO.class);
    return this.getQuestion(questionID);
  }

  /*
   * (non-Javadoc)
   * 
   * @see example.business.api.topic.services.TopicService#getTotalQuestions()
   */
  @Override
  public long getTotalQuestions(Boolean deleted) {
    Query query = new Query();
    if (deleted != null) {
      query.addCriteria(Criteria.where("deleted").is(deleted));
    }
    return this.mongoTemplate.count(query, TopicQuestionDO.class);
  }

  /*
   * (non-Javadoc)
   * 
   * @see example.business.api.topic.services.TopicService#addAnswer(long, java.lang.String)
   */
  @Override
  public Answer addAnswer(long questionID, String answerContent) {
    Question question = this.getQuestion(questionID);
    if (question == null) {
      throw new IllegalArgumentException();
    }
    TopicAnswerDO topicAnswerDO = new TopicAnswerDO();
    topicAnswerDO.setId(this.idService.nextID(SystemIDSchema.Topic_Answer));
    topicAnswerDO.setCommentcount(0);
    topicAnswerDO.setQuestionID(questionID);
    topicAnswerDO.setSysInsertTime(new Date());
    topicAnswerDO.setAnswerContent(answerContent);
    this.mongoTemplate.insert(topicAnswerDO);

    Query query = Query.query(Criteria.where("_id").is(questionID));
    Update update = new Update().inc("answercount", 1);
    this.mongoTemplate.updateFirst(query, update, TopicQuestionDO.class);
    return BeanUtil.toAnswer(topicAnswerDO, question);
  }

  /*
   * (non-Javadoc)
   * 
   * @see example.business.api.topic.services.TopicService#getAnswer(long)
   */
  @Override
  public Answer getAnswer(long answerID) {
    TopicAnswerDO topicAnswerDO = this.mongoTemplate.findById(answerID, TopicAnswerDO.class);
    if (topicAnswerDO == null) {
      return null;
    }
    return BeanUtil.toAnswer(topicAnswerDO, this.getQuestion(topicAnswerDO.getQuestionID()));
  }

  /*
   * (non-Javadoc)
   * 
   * @see example.business.api.topic.services.TopicService#getAnswers(long, long, long)
   */
  @Override
  public List<Answer> getAnswers(long questionID, long offset, long limit) {
    Question question = this.getQuestion(questionID);
    MyAssert.objectInitialized(question);
    Query query = new Query(Criteria.where("questionID").is(questionID));
    query.skip((int) offset);
    query.limit((int) limit);
    List<TopicAnswerDO> topicAnswerDOs = this.mongoTemplate.find(query, TopicAnswerDO.class);
    if (topicAnswerDOs == null || topicAnswerDOs.size() <= 0) {
      return null;
    }
    List<Answer> answers = new ArrayList<>();
    for (TopicAnswerDO topicAnswerDO : topicAnswerDOs) {
      Answer answer = BeanUtil.toAnswer(topicAnswerDO, question);
      answers.add(answer);
    }
    return answers;
  }

  /*
   * (non-Javadoc)
   * 
   * @see example.business.api.topic.services.TopicService#geTotalAnswers(long)
   */
  @Override
  public long geTotalAnswers(long questionID) {
    Query query = new Query(Criteria.where("questionID").is(questionID));
    return this.mongoTemplate.count(query, TopicAnswerDO.class);
  }

  /*
   * (non-Javadoc)
   * 
   * @see example.business.api.topic.services.TopicService#deleteAnswer(long)
   */
  @Override
  public void deleteAnswer(long answerID) {
    Answer answer = this.getAnswer(answerID);
    if (answer == null) {
      return;
    }
    Question question = answer.getQuestion();
    Query query = Query.query(Criteria.where("_id").is(answerID));
    this.mongoTemplate.remove(query, TopicAnswerDO.class);
    Query question_query = Query.query(Criteria.where("_id").is(question.getId()));
    Update update = new Update();
    update.inc("answercount", -1);
    this.mongoTemplate.updateFirst(question_query, update, TopicQuestionDO.class);
  }

  /*
   * (non-Javadoc)
   * 
   * @see example.business.api.topic.services.TopicService#addQuestionComment(long,
   * java.lang.String)
   */
  @Override
  public QuestionComment addQuestionComment(long questionID, String commentContent) {
    return null;
  }

  /*
   * (non-Javadoc)
   * 
   * @see example.business.api.topic.services.TopicService#addAnswerComment(long, java.lang.String)
   */
  @Override
  public AnswerComment addAnswerComment(long answerID, String commentContent) {
    // TODO Auto-generated method stub
    return null;
  }

  /*
   * (non-Javadoc)
   * 
   * @see example.business.api.topic.services.TopicService#deleteComment(long)
   */
  @Override
  public void deleteComment(long commentID) {
    // TODO Auto-generated method stub

  }

  /*
   * (non-Javadoc)
   * 
   * @see example.business.api.topic.services.TopicService#getQuestionComments(long)
   */
  @Override
  public List<QuestionComment> getQuestionComments(long questonID) {
    // TODO Auto-generated method stub
    return null;
  }

  /*
   * (non-Javadoc)
   * 
   * @see example.business.api.topic.services.TopicService#getAnswerComments(long)
   */
  @Override
  public List<AnswerComment> getAnswerComments(long answerID) {
    // TODO Auto-generated method stub
    return null;
  }

  private boolean __exist_questionid(long questionid) {
    return this.mongoTemplate.exists(new Query(Criteria.where("_id").is(questionid)), TopicQuestionDO.class);
  }

}
